package com.hk.system.controller;


import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hk.domain.entity.User;
import com.hk.domain.service.UserService;
import com.hk.mybatis.result.ResponseEntityResult;
import com.hk.security.authentication.ProductUserInfo;
import com.hk.system.request.UserLoginRequest;
import dubhe.token.api.authentication.principal.Principal;
import dubhe.token.api.factory.TimeoutTokenFactory;
import dubhe.token.api.factory.TokenFactory;
import dubhe.token.api.model.TimeoutAccessToken;
import dubhe.token.api.model.Token;
import dubhe.token.api.registry.TokenRegistry;
import dubhe.token.core.model.UserInfo;
import dubhe.token.core.util.SecurityContextUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.Optional;

/**
 * @author miaoj
 */
@RestController
@RequestMapping
@Tag(name = "用户登录登出 api", description = "用户登录登出 api")
public class LoginController {

    private final TokenFactory tokenFactory;
    private final TokenRegistry tokenRegistry;
    private final UserService userService;
    private final PasswordEncoder passwordEncoder;

    public LoginController(@Qualifier(TokenFactory.BEAN_NAME) TokenFactory tokenFactory,
                           TokenRegistry tokenRegistry, UserService userService, PasswordEncoder passwordEncoder) {
        this.tokenFactory = tokenFactory;
        this.tokenRegistry = tokenRegistry;
        this.userService = userService;
        this.passwordEncoder = passwordEncoder;
    }

    /**
     * 登录
     */
    @Operation(summary = "用户登录", description = "用户登录")
    @PostMapping(value = "/rest/login")
    public Object login(@Valid @RequestBody UserLoginRequest request) throws Exception {
        final Optional<User> userOptional = userService.getOneOpt(Wrappers.<User>lambdaQuery().eq(User::getAccount, request.getUsername()));
        if (userOptional.isEmpty()) {
            return ResponseEntityResult.error(String.format("用户'%s'不存在", request.getUsername()));
        }
        final User user = userOptional.get();
        if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
            return ResponseEntityResult.error("密码不正确");
        }
        final ProductUserInfo userInfo = ProductUserInfo
                .builder()
                .loginName(user.getAccount())
                .name(user.getName())
                .id(user.getId())
                .type(user.getType())
                .authenticated(true)
                .lastOpened(user.getLastOpened())
                .build();
        final dubhe.token.api.authentication.Authentication tokenAuthentication = new dubhe.token.api.authentication.Authentication(
                Principal.builder()
                        .id(userInfo.getLoginName())
                        .userInfo(userInfo)
                        .build());
        final TimeoutTokenFactory factory = (TimeoutTokenFactory) tokenFactory.get(TimeoutAccessToken.class);
        Token token = factory.create(tokenAuthentication);
        userInfo.setAccessToken(token.getId());
        try {
            tokenRegistry.addToken(token);
        } catch (Exception e) {
            throw new RuntimeException("生成token出错");
        }
        return ResponseEntityResult.success(userInfo);
    }

    /**
     * @since 3.0
     */
    @Operation(summary = "用户登出")
    @PostMapping("/rest/logout")
    public Object logout(HttpServletRequest request, HttpServletResponse response) throws Exception {
        final UserInfo currentUserInfo = SecurityContextUtil.getCurrentUserInfo();
        if (currentUserInfo.isAuthenticated()) {
            tokenRegistry.deleteToken(currentUserInfo.getAccessToken());
        }
        Cookie tokenCookie = new Cookie("ACCESS_TOKEN", null);
        tokenCookie.setPath("/");
        tokenCookie.setMaxAge(0);
        response.addCookie(tokenCookie);
        return ResponseEntityResult.success("登出成功");
    }
}
